package com.nulldev.util.concurrency.threadIt.v4.utils.impls;

import java.util.List;

import com.nulldev.util.JVM.Exceptions;
import com.nulldev.util.VariableAPI.ArrayUtils;
import com.nulldev.util.concurrency.threadIt.v4.emapi.uft.Executable;
import com.nulldev.util.data.Variables;
import com.nulldev.util.data.Arrays.arrays.FastLists;
import com.nulldev.util.io.IOUtils;

public class TaskUtils {

	public static void assertIfRunning(final Executable<?> exec) {
		Variables.checkArgument(exec.isRunning(), "Task is already running, state is %s", exec.status());
	}

	public static String generate_trace(final Executable<?> task) {
		return generate_trace(task, false);
	}

	public static String generate_trace(final Executable<?> task, final boolean disableResultPrinting) {
		Variables.requireNonNull(task, "task");

		final StringBuilder sb = new StringBuilder(IOUtils.STRING_ALLOC_BUFFER);
		appendTo(task, sb, disableResultPrinting);
		return sb.toString();
	}

	public static String generate_trace_with_fallback(final Executable<?> task, final Throwable trace) {
		return generate_trace_with_fallback(task, trace, false);
	}

	public static String generate_trace_with_fallback(final Executable<?> task, final Throwable trace, final boolean disableResultPrinting) {
		Variables.requireNonNull(task, "task");
		Variables.requireNonNull(trace, "trace");

		final StringBuilder sb = new StringBuilder(IOUtils.STRING_ALLOC_BUFFER);
		appendTo(task, sb, disableResultPrinting, trace);
		return sb.toString();
	}

	private static void appendTo(final Executable<?> e, final StringBuilder sb, final boolean disableResultPrinting) {
		appendTo(e, sb, disableResultPrinting, null);
	}

	private static void appendTo(final Executable<?> e, final StringBuilder sb, final boolean disableResultPrinting, final Throwable fallback) {
		/* If we're not RUNNING then fallback to the FutureTask creation stack. */
		if (e.hasExecutingThread() && e.isRunning()) {
			sb.append(e.toString(disableResultPrinting));
			sb.append("\n");
			sb.append(Exceptions.getStackTrace(e.getExecutingThread().getStackTrace()));
		} else if (e.hasTrace()) {
			sb.append(e.toString(disableResultPrinting));
			sb.append("\n");
			sb.append(Exceptions.getStackTrace(e.getTrace().getStackTrace()));
		} else if (fallback != null) {
			sb.append(e.toString(disableResultPrinting));
			sb.append("\n");
			sb.append(Exceptions.getStackTrace(fallback.getStackTrace()));
		} else {
			/* NO-OP */
		}
	}

	public static void printWithTrace(final Executable<?>... o) {
		printWithTrace(false, o);
	}

	public static void printWithTrace(final boolean disableResultPrinting, final Executable<?>... o) {
		final List<Object> p = FastLists.list(o);
		for (int i = 0; i < p.size(); i++) {
			final Executable<?> e = (Executable<?>) p.get(i);
			final StringBuilder sb = new StringBuilder(IOUtils.STRING_ALLOC_BUFFER);
			appendTo(e, sb, disableResultPrinting);
			p.set(i, sb.toString());
		}
		ArrayUtils.printLln(p);
	}

	public static void printWithTrace(final List<Executable<?>> o) {
		printWithTrace(false, o);
	}

	public static void printWithTrace(final boolean disableResultPrinting, final List<Executable<?>> o) {
		final List<Object> p = FastLists.list(o);
		for (int i = 0; i < p.size(); i++) {
			final Executable<?> e = (Executable<?>) p.get(i);
			final StringBuilder sb = new StringBuilder(IOUtils.STRING_ALLOC_BUFFER);
			appendTo(e, sb, disableResultPrinting);
			p.set(i, sb.toString());
		}
		ArrayUtils.printLln(p);
	}
}
